package com.dhcc.bpm.modules.scf.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dhcc.bpm.common.segmentId.LocalCacheIdGenerator;
import com.dhcc.bpm.modules.scf.entity.OcrResult;
import com.dhcc.bpm.modules.scf.entity.ScfFileAttachmentInfo;
import com.dhcc.bpm.modules.scf.mapper.ScfFileAttachmentInfoMapper;
import com.dhcc.bpm.modules.scf.service.IScfFileAttachmentInfoService;
import com.dhcc.bpm.modules.scf.util.OBSUtil;
import com.dhcc.bpm.modules.scf.util.OCRUtil;
import com.dhcc.bpm.modules.scf.vo.ScfFileAttachmentInfoVO.ScfFileAttachmentInfoVO;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 文件附件表实现类
 * liuguoting
 * 2023-09-15
 */
@Service
@EnableScheduling
public class ScfFileAttachmentInfoServiceImpl extends ServiceImpl<ScfFileAttachmentInfoMapper, ScfFileAttachmentInfo> implements IScfFileAttachmentInfoService {
    @Autowired
    private OBSUtil obsUtil;
    @Autowired
    private ScfFileAttachmentInfoMapper scfFileAttachmentInfoMapper;
    @Autowired
    private LocalCacheIdGenerator localCacheIdGenerator;
    @Value("${ocr.ak}")
    private String ak;

    @Value("${ocr.sk}")
    private String sk;

    @Value("${ocr.projectId}")
    private String projectId;

    @Value("${ocr.endpoint}")
    private String endpoint;
    /**
     * 上传接口
     *
     * @param file
     * @return
     */
    @Override
    public ScfFileAttachmentInfoVO uploadFile(String operatorId, String fileType, MultipartFile file ,String associationId, String fileCategory) throws Exception {
        // 生成上传日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr = sdf.format(new Date());
        // 生成时间
        SimpleDateFormat timeFormat = new SimpleDateFormat("HHmmss");
        String formTime = timeFormat.format(new Date());
        // 生成文件存储路径和文件名
        // 1.获取上传的文件原始名称
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        // 1.1获取拓展名
        String fileExtension = "";
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex != -1) {
            fileExtension = fileName.substring(dotIndex + 1).toLowerCase();
        }
        // 1.2判断文件后缀是否为图片
        // 1.2.1创建一个是否为图片的变量
        boolean isImage;
        if (!fileExtension.equals("png") && !fileExtension.equals("jpeg") && !fileExtension.equals("jpg") && !fileExtension.equals("gif")) {
            isImage = false;
        } else {
            isImage = true;
        }
        // 1.2.2创建一个是否为PDF的变量
        boolean isPdf;
        if (!fileExtension.equals("pdf")) {
            isPdf = false;
        } else {
            isPdf = true;
        }
        // 2.组合文件名称（例如：企业营业执照_营业执照.pdf）
        String fileStorageName = localCacheIdGenerator.nextId() + "_" + fileType + "_" + fileName; // 您可以生成唯一的文件名

        // 保存文件到obs
        HashMap<String, String> stringStringHashMap = obsUtil.uploadFile(file, fileStorageName);
        OcrResult ocrResult = new OcrResult();
        if (fileType.equals("businessLicense") || fileType.equals("corporateIdPhoto") || fileType.equals("individualIdPhoto")) {
            // 获取文件的Base64编码
            byte[] fileBytes = file.getBytes();
            String base64EncodedFile = Base64.getEncoder().encodeToString(fileBytes);
            // 调用ocr接口
            OCRUtil ocrUtil = new OCRUtil();
            ocrResult = ocrUtil.getOcr(base64EncodedFile, fileType, ak, sk, projectId, endpoint);
        }
        // 创建文件附件记录并保存到对象中
        // 生成ROW_ID
        String rowId = "FJ" + localCacheIdGenerator.nextId() + formTime;
        ScfFileAttachmentInfoVO fileInfo = new ScfFileAttachmentInfoVO();
        // 设置记录编号
        fileInfo.setRowId(rowId);
        // 设置附件类型
        fileInfo.setFileType(fileType);
        // 设置文件原始名称
        fileInfo.setFileName(fileName);
        // 设置文件存储名称
        fileInfo.setFileStorageName(fileStorageName);
        // 设置文件存储路径
        fileInfo.setFilePath(stringStringHashMap.get("objectKey"));
        // 设置文件是否为图片
        fileInfo.setIsImage(isImage);
        // 设置文件是否为PDF
        fileInfo.setIsPdf(isPdf);
        // 设置文件上传时间
        fileInfo.setGetDate(dateStr);
        // 设置上传人员ID
        fileInfo.setOperatorId(operatorId);
        fileInfo.setAssociationId( associationId);

        // 设置分类标识 - 用于区分单据和车辆的上传与预览
        fileInfo.setFileCategory(fileCategory);
        // 设置主体信息对象
        if (fileType.equals("businessLicense") || fileType.equals("corporateIdPhoto") || fileType.equals("individualIdPhoto")) {
            fileInfo.setScfSubjectBasicInfo(ocrResult.getScfSubjectBasicInfo());
            fileInfo.setIdCardJust(ocrResult.getIdCardJust());
            fileInfo.setIdCardBack(ocrResult.getIdCardBack());
        }
        return fileInfo;
    }

    /**
     * 批量给记录插入对应功能记录的主键
     *
     * @param rowIds
     * @param newValue
     */
    @Override
    public void batchUpdateField(List<String> rowIds, String newValue) {
        scfFileAttachmentInfoMapper.batchUpdateField(rowIds, newValue);
    }

    /**
     * 根据关联编号删除记录所对应的全部文件
     *
     * @param newValue
     * @return
     */
    @Override
    public boolean batchDeleteFile(String newValue) {
        int rowNum = scfFileAttachmentInfoMapper.batchDeleteFile(newValue);
        if (rowNum >= 1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 更新文件附件时，删除旧文件记录。
     *
     * @param rowId
     * @return
     */
    @Override
    public boolean deleteByOldFileInfo(String rowId) {
        int rowNum = baseMapper.deleteByOldFileInfo(rowId);
        if (rowNum >= 1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据关联编号查询记录多所对应的全部文件信息
     *
     * @param newValue
     * @return
     */
    @Override
    public List<ScfFileAttachmentInfoVO> selectAllByAssociationId(String newValue) {
        return scfFileAttachmentInfoMapper.selectAllByAssociationId(newValue);
    }

    /**
     * 获取指定文件rowId记录的存储路径
     * @param rowId
     * @return
     */
    @Override
    public String getFilePath(String rowId ,String fileCategory ) {
        return scfFileAttachmentInfoMapper.getFilePath(rowId ,fileCategory);
    }

    /**
     * 上传并更新文件附件表字段
     * @param operatorId
     * @param fileType
     * @param file
     * @return
     * @throws Exception
     */
    @Override
    public ScfFileAttachmentInfoVO uploadAttachment(String operatorId, String fileType, MultipartFile file ,String associationId, String fileCategory ) throws Exception {
        // 接收上传人id，附件类型，文件。
        // 调用上传接口，完成文件上传。
        ScfFileAttachmentInfoVO scfFileAttachmentInfo = uploadFile(operatorId, fileType, file ,associationId, fileCategory);
        // 获取记录ID
        // 将对象保存到数据库中
        save(scfFileAttachmentInfo);
        // 将记录id返回给前端
        return scfFileAttachmentInfo;
    }

    /**
     * 根据id数组，返回多个文件流
     *
     * @param rowIds
     * @return
     * @throws IOException
     */
    @Override
    public List<Kv> fileDetails(List<String> rowIds, String fileCategory) throws IOException {
        List<Kv> FileList = new ArrayList<>();

        for (String rowId : rowIds) {
            // 根据传入编号以及分类标识获取文件(分类标识用于判断获取的是单据还是车辆)对应的存储路径
            String objectKey = getFilePath(rowId,fileCategory);
            if (objectKey != null ){
                // 调用OBS文件读取流方法，处理文件并添加到键值对中
                byte[] obsFileBytes = obsUtil.downloadFileAsBytes(objectKey);
                String fileBytes = Base64.getEncoder().encodeToString(obsFileBytes);
                ScfFileAttachmentInfo scfFileAttachmentInfo = getById(rowId);
                boolean isPdf = scfFileAttachmentInfo.getIsPdf();
                boolean isImage = scfFileAttachmentInfo.getIsImage();
                Kv kv = Kv.create().set("key", rowId).set("file", fileBytes).set("isPdf", isPdf).set("isImage", isImage);
                FileList.add(kv);
            }
        }
        return FileList;
    }




    /**
     * 将被替换的文件关联id置为空
     *
     * @param rowId
     * @return
     */
    @Override
    public Boolean updataFiledNull(String rowId) {
        int rowNum = scfFileAttachmentInfoMapper.updataFiledNull(rowId);
        if (rowNum >= 1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据文件id将文件临时路径更新为正式路径
     * @param rowId
     * @param objectKey
     * @return
     */
    @Override
    public Boolean updateFilePath(String rowId, String objectKey) {
        int rowNum = baseMapper.updateFilePath(rowId, objectKey);
        if (rowNum >= 1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据其他模块中记录的编号查询对应附件文件的RowId
     * @param rowId
     * @return
     */
    @Override
    public List<String> selectAssociationIdByRowId(String rowId) {
        return baseMapper.selectAssociationIdByRowId(rowId);
    }

    /**
     * 删除本地数据库中的文件记录，同步删除obs中存储的文件
     * @param rowId
     * @return
     */
    @Override
    public R<Boolean> deleteFileByRowId(String rowId) {
        // 根据文件编号获取文件的存储路径
        String objectKey = getFilePath(rowId, null);
        // 删除本地数据库中的文件记录
        boolean removeFileByRowId = removeFileByRowId(rowId);
        // 删除 obs 上的文件
        Boolean isDeleteFile = obsUtil.deleteFile(objectKey);
        if (Boolean.FALSE.equals(isDeleteFile) && Boolean.FALSE.equals(removeFileByRowId)) {
            return R.fail("处理失败！");
        }
        if (Boolean.TRUE.equals(isDeleteFile) && Boolean.TRUE.equals(removeFileByRowId)) {
            // 处理成功后，返回成功响应
            return R.success("处理成功！");
        } else {
            return R.fail("文件删除失败！");
        }
    }
    public boolean removeFileByRowId(String rowId){
        int rowCount = baseMapper.deleteByFileRowId(rowId);
        return rowCount > 0;
    }




}
